#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "typedef.h"
#include "gps.h"
typedef enum
{
    GPS_SRC_GPS, // GPS
    GPS_SRC_GLONASS,
    GPS_SRC_BD,
    GPS_SRC_QZSS,
    GPS_SRC_OTHER,
} gps_data_src_e; // GPS数据源

typedef struct
{
    uint8_t talker[3];
    uint8_t SentenceFormatter[4];
} gps_address_t;

typedef struct
{
    int utc_year;
    int utc_mon;
    int utc_day;
    int utc_hour;
    int utc_min;
    int utc_sec;
    int utc_msec;
} gps_data_utc_t;

typedef enum
{
    LOCATION_INVALID,
    LOCATION_NORMAL,
} gps_location_state_e;

typedef enum
{
    HEMISPHERE_EAST,  // 东
    HEMISPHERE_SOUTH, // 南
    HEMISPHERE_WEST,  // 西
    HEMISPHERE_NORTH, // 北

} gps_course_e;
typedef enum
{
    MODE_INDICATION_A, // 自主定位
    MODE_INDICATION_D, // 差分
    MODE_INDICATION_E, // 估算
    MODE_INDICATION_N, // 数据无效
} gps_mode_indication_e;
//$GNRMC,090944.000,V,,,,,,,161222,,,N,V*2D
typedef struct
{
    gps_data_utc_t utc;                    // utc时间 yy mm dd hh mm ss.sss
    gps_location_state_e location_state;   // 定位状态
    double latitude;                       // 纬度
    gps_course_e latitude_hemisphere;      // 纬度半球
    double longitude;                      // 经度
    gps_course_e longitude_hemisphere;     // 经度半球
    double ground_speed;                   // 地面速率
    double ground_course;                  // 地面航向
    double declination;                    // 磁偏角
    gps_course_e declination_course;       // 磁偏角方向
    gps_mode_indication_e mode_indication; // 模式指示

} gps_data_rmc_t;

//$GNGGA,090945.004,3205.20197,N,11852.59108,E,1,06,5.1,9.7,M,0.9,M,,*71
typedef struct
{
    gps_data_utc_t utc;                  // utc时间 yy mm dd hh mm ss.sss
    double latitude;                     // 纬度
    gps_course_e latitude_hemisphere;    // 纬度半球
    double longitude;                    // 经度
    gps_course_e longitude_hemisphere;   // 经度半球
    gps_location_state_e location_state; // 定位状态
    int satellites_count;                // 卫星数量
    double precision_level;              // 水平精度
    double sea_level;                    // 天线距海平面高度
    double ground_level;                 // 大地水准面高度
    int differential_data_life;          // 差分 GPS 数据期限
    int differential_data_bsn;           // 差分 GPS 数据基站标号
} gps_data_gga_t;

//$GPGSV,2,1,05,04,49,243,34,08,57,215,36,09,35,291,37,27,,,29,0*5E
#define GSV_NUM_MAX (20)
typedef struct
{
    int message_num;                      // 电文数
    int message_index;                    // 语句号
    int visible_count;                    // 可视卫星总数
    int satellite_index[GSV_NUM_MAX];     // 卫星编号
    int satellite_elevation[GSV_NUM_MAX]; // 卫星仰角
    int satellite_azimuth[GSV_NUM_MAX];   // 卫星方位角
    int satellite_snr[GSV_NUM_MAX];       // 卫星信噪比
    int signalid;                         // 信号标识符

} gps_data_gsv_t;

typedef enum
{
    LOCATION_MODE_AUTO,             // 自动
    LOCATION_MODE_MANUAL_OPERATION, // 手动
} gps_location_mode_e;
typedef enum
{
    LOCATION_TYPE_N,  // 没有定位
    LOCATION_TYPE_2D, // 二维定位
    LOCATION_TYPE_3D, // 三维定位

} gps_location_type_e;
//$GNGSA,A,3,10,36,40,,,,,,,,,,8.0,5.1,6.2,4*3C
typedef struct
{
    gps_location_mode_e mode;         // 定位模式
    gps_location_type_e type;         // 定位形式
    int satellite_index[GSV_NUM_MAX]; // 卫星编号
    double PDOP;                      // 位置精度因子
    double HDOP;                      // 水平精度因子
    double VDOP;                      // 垂直精度因子
    int systemid;                     // 系统标识符

} gps_data_gsa_t;

//$GNVTG,,,,,,,,,N*2E
typedef struct
{
    int ground_course_true;                // 以真北为参考基准的地面航向
    int ground_course_magnetic;            // 以磁北为参考基准的地面航向
    double ground_speed_knot;              // 地面速率(节)
    double ground_speed_km;                // 地面速率(km/h)
    gps_mode_indication_e mode_indication; // 模式指示

} gps_data_vtg_t;

typedef struct
{
    double latitude;                       // 纬度
    gps_course_e latitude_hemisphere;      // 纬度半球
    double longitude;                      // 经度
    gps_course_e longitude_hemisphere;     // 经度半球
    gps_data_utc_t utc;                    // utc时间 yy mm dd hh mm ss.sss
    gps_location_state_e location_state;   // 定位状态
    gps_mode_indication_e mode_indication; // 模式指示

} gps_data_gll_t;

typedef struct
{
    gps_data_utc_t utc; // utc时间 yy mm dd hh mm ss.sss
    int day;            // 日
    int mon;            // 月
    int year;           // 年
    int localhour;      // 暂不支持
    int localmin;       // 暂不支持

} gps_data_zda_t;

typedef struct
{
    int total;     // 语句总数
    int index;     // 语句编号
    int flag;      // 文本标识符
    char txt[120]; // 文本信息

} gps_data_txt_t;

typedef struct
{
    gps_data_rmc_t rmc;
    gps_data_gga_t gga;
    gps_data_gsv_t gsv;
    gps_data_gsa_t gsa;
    gps_data_vtg_t vtg;
    gps_data_gll_t gll;
    gps_data_zda_t zda;
    gps_data_txt_t txt;

} gps_data_t;

typedef struct
{
    gps_address_t address;
    gps_data_t data;
    uint8_t checksum;

} gps_t;
static gps_t gps = {0};
static int gps_get_dot_count(char *str)
{
    if (str == NULL)
    {
        return 0;
    }

    int dot_count = 0;
    while (*str)
    {
        if (*str == ',')
        {
            dot_count++;
        }
        str++;
    }
    printf("dot count [%d]\n", dot_count);
    return dot_count;
}

static void gps_parse_rmc(char *str)
{
    if (str == NULL)
    {
        return;
    }

    char buf[20] = {0};
    int index = 0, len = 0, len_count = 0, dot_count = 0, last_len = 0;
    for (int i = 0; i <= strlen(str); i++)
    {
        // printf("[%c]\t", str[i]);
        if (str[i] == ',' || str[i] == '*' || i == strlen(str))
        {
            if (len > 0)
            {
                memset(buf, 0, sizeof(buf));

                memcpy(buf, str + i - len, len);

                printf("[%s] ", buf);

                switch (dot_count)
                {
                case 1: // 获取UTC时间
                {
                    sscanf(buf, "%02d%02d%02d.%03d",
                           &gps.data.rmc.utc.utc_hour,
                           &gps.data.rmc.utc.utc_min,
                           &gps.data.rmc.utc.utc_sec,
                           &gps.data.rmc.utc.utc_msec);
                }
                break;
                case 2: // 获取定位状态
                {
                    if (strcmp(buf, "A") == 0)
                    {
                        gps.data.rmc.location_state = LOCATION_NORMAL;
                    }
                    else if (strcmp(buf, "V") == 0)
                    {
                        gps.data.rmc.location_state = LOCATION_INVALID;
                    }
                }
                break;
                case 3: // 获取纬度
                {
                    sscanf(buf, "%lf", &gps.data.rmc.latitude);
                }
                break;
                case 4: // 获取纬度半球
                {
                    if (strcmp(buf, "N") == 0)
                    {
                        gps.data.rmc.latitude_hemisphere = HEMISPHERE_NORTH;
                    }
                    else if (strcmp(buf, "S") == 0)
                    {
                        gps.data.rmc.latitude_hemisphere = HEMISPHERE_SOUTH;
                    }
                }
                break;
                case 5: // 获取经度
                {
                    sscanf(buf, "%lf", &gps.data.rmc.longitude);
                }
                break;
                case 6: // 获取经度半球
                {
                    if (strcmp(buf, "E") == 0)
                    {
                        gps.data.rmc.longitude_hemisphere = HEMISPHERE_EAST;
                    }
                    else if (strcmp(buf, "W") == 0)
                    {
                        gps.data.rmc.longitude_hemisphere = HEMISPHERE_WEST;
                    }
                }
                break;
                case 7: // 获取地面速率
                {
                    sscanf(buf, "%lf", &gps.data.rmc.ground_speed);
                }
                break;
                case 8: // 获取地面航向
                {
                    sscanf(buf, "%lf", &gps.data.rmc.ground_course);
                }
                break;
                case 9: // 获取UTC日期
                {
                    sscanf(buf, "%02d%02d%02d",
                           &gps.data.rmc.utc.utc_day,
                           &gps.data.rmc.utc.utc_mon,
                           &gps.data.rmc.utc.utc_year);
                }
                break;
                case 10: // 获取磁偏角
                {
                    sscanf(buf, "%lf", &gps.data.rmc.declination);
                }
                break;
                case 11: // 获取磁偏角方向
                {
                    if (strcmp(buf, "E") == 0)
                    {
                        gps.data.rmc.declination_course = HEMISPHERE_EAST;
                    }
                    else if (strcmp(buf, "W") == 0)
                    {
                        gps.data.rmc.declination_course = HEMISPHERE_WEST;
                    }
                }
                break;
                case 12: // 获取模式指示
                {
                    if (strcmp(buf, "A") == 0)
                    {
                        gps.data.rmc.mode_indication = MODE_INDICATION_A;
                    }
                    else if (strcmp(buf, "D") == 0)
                    {
                        gps.data.rmc.mode_indication = MODE_INDICATION_D;
                    }
                    else if (strcmp(buf, "E") == 0)
                    {
                        gps.data.rmc.mode_indication = MODE_INDICATION_E;
                    }
                    else if (strcmp(buf, "N") == 0)
                    {
                        gps.data.rmc.mode_indication = MODE_INDICATION_N;
                    }
                }
                break;

                default:
                    break;
                }
            }
            len = 0;
            dot_count++;
        }
        else
        {
            len++;
        }
    }

    printf("dot count[%d]\n", dot_count);
}
static void gps_parse_gga(char *str)
{
    if (str == NULL)
    {
        return;
    }

    char buf[20] = {0};
    int index = 0, len = 0, len_count = 0, dot_count = 0, last_len = 0;
    for (int i = 0; i <= strlen(str); i++)
    {
        // printf("[%c]\t", str[i]);
        if (str[i] == ',' || str[i] == '*' || i == strlen(str))
        {
            if (len > 0)
            {
                memset(buf, 0, sizeof(buf));

                memcpy(buf, str + i - len, len);

                printf("[%s] ", buf);

                switch (dot_count)
                {
                case 1: // 获取UTC时间
                {
                    sscanf(buf, "%02d%02d%02d.%03d",
                           &gps.data.gga.utc.utc_hour,
                           &gps.data.gga.utc.utc_min,
                           &gps.data.gga.utc.utc_sec,
                           &gps.data.gga.utc.utc_msec);
                }
                break;
                case 2: // 获取纬度
                {
                    sscanf(buf, "%lf", &gps.data.gga.latitude);
                }
                break;
                case 3: // 获取纬度半球
                {
                    if (strcmp(buf, "N") == 0)
                    {
                        gps.data.gga.latitude_hemisphere = HEMISPHERE_NORTH;
                    }
                    else if (strcmp(buf, "S") == 0)
                    {
                        gps.data.gga.latitude_hemisphere = HEMISPHERE_SOUTH;
                    }
                }
                break;
                case 4: // 获取经度
                {
                    sscanf(buf, "%lf", &gps.data.gga.longitude);
                }
                break;
                case 5: // 获取经度半球
                {
                    if (strcmp(buf, "E") == 0)
                    {
                        gps.data.gga.longitude_hemisphere = HEMISPHERE_EAST;
                    }
                    else if (strcmp(buf, "W") == 0)
                    {
                        gps.data.gga.longitude_hemisphere = HEMISPHERE_WEST;
                    }
                }
                break;
                case 6: // 获取定位质量指示
                {
                    if (strcmp(buf, "0") == 0)
                    {
                        gps.data.gga.location_state = LOCATION_INVALID;
                    }
                    else
                    {
                        gps.data.gga.location_state = LOCATION_NORMAL;
                    }
                }
                break;
                case 7: // 获取使用卫星数量
                {
                    sscanf(buf, "%d", &gps.data.gga.satellites_count);
                }
                break;
                case 8:
                {
                    sscanf(buf, "%lf", &gps.data.gga.precision_level);
                }
                break;
                case 9:
                {
                    sscanf(buf, "%lf", &gps.data.gga.sea_level);
                }
                break;
                case 11:
                {
                    sscanf(buf, "%lf", &gps.data.gga.ground_level);
                }
                break;
                case 13:
                {
                    sscanf(buf, "%d", &gps.data.gga.differential_data_life);
                }
                break;
                case 14:
                {
                    sscanf(buf, "%d", &gps.data.gga.differential_data_bsn);
                }
                break;
                default:
                    break;
                }
            }
            len = 0;
            dot_count++;
        }
        else
        {
            len++;
        }
    }

    printf("dot count[%d]\n", dot_count);
}
static void gps_parse_gsv(char *str)
{
    if (str == NULL)
    {
        return;
    }

    int dot_c = gps_get_dot_count(str);

    char buf[20] = {0};
    int index = 0, len = 0, len_count = 0, dot_count = 0, index_2 = 0;
    for (int i = 0; i <= strlen(str); i++)
    {
        // printf("[%c]\t", str[i]);
        if (str[i] == ',' || str[i] == '*' || i == strlen(str))
        {
            if (len > 0)
            {
                memset(buf, 0, sizeof(buf));

                memcpy(buf, str + i - len, len);
                printf("[%s] ", buf);

                switch (dot_count)
                {
                case 1: // 获取电文数
                {
                    sscanf(buf, "%02d", &gps.data.gsv.message_num);
                }
                break;
                case 2: // 获取语句号
                {
                    sscanf(buf, "%02d", &gps.data.gsv.message_index);
                }
                break;
                case 3: // 获取可视卫星总数
                {
                    sscanf(buf, "%02d", &gps.data.gsv.visible_count);
                }
                break;
                default: // 卫星参数
                {
                    if (dot_count == dot_c)
                    {
                        sscanf(buf, "%d", &gps.data.gsv.signalid);
                        break;
                    }

                    index = (dot_count - 4) % 4;
                    index_2 = (dot_count - 4) / 4;
                    switch (index)
                    {
                    case 0: // 卫星号
                    {
                        sscanf(buf, "%d", &gps.data.gsv.satellite_index[index_2]);
                    }
                    break;
                    case 1: // 仰角
                    {
                        sscanf(buf, "%d", &gps.data.gsv.satellite_elevation[index_2]);
                    }
                    break;
                    case 2: // 方位角
                    {
                        sscanf(buf, "%d", &gps.data.gsv.satellite_azimuth[index_2]);
                    }
                    break;
                    case 3: // 信噪比
                    {
                        sscanf(buf, "%d", &gps.data.gsv.satellite_snr[index_2]);
                    }
                    break;
                    default:
                        break;
                    }
                }
                break;
                }
            }
            len = 0;
            dot_count++;
        }
        else
        {
            len++;
        }
    }

    printf("dot count[%d]\n", dot_count);
}
static void gps_parse_gsa(char *str)
{
    if (str == NULL)
    {
        return;
    }

    char buf[20] = {0};
    int index = 0, len = 0, len_count = 0, dot_count = 0, sate_index = 0;
    int dot_c = gps_get_dot_count(str);

    for (int i = 0; i <= strlen(str); i++)
    {
        // printf("[%c]\t", str[i]);
        if (str[i] == ',' || str[i] == '*' || i == strlen(str))
        {
            if (len > 0)
            {
                memset(buf, 0, sizeof(buf));

                memcpy(buf, str + i - len, len);

                printf("[%s] ", buf);

                switch (dot_count)
                {
                case 1: // 获取模式
                {
                    if (strcmp(buf, "M") == 0)
                    {
                        gps.data.gsa.mode = LOCATION_MODE_MANUAL_OPERATION;
                    }
                    else if (strcmp(buf, "A") == 0)
                    {
                        gps.data.gsa.mode = LOCATION_MODE_AUTO;
                    }
                }
                break;
                case 2: // 获取定位形式
                {
                    if (strcmp(buf, "1") == 0)
                    {
                        gps.data.gsa.type = LOCATION_TYPE_N;
                    }
                    else if (strcmp(buf, "2") == 0)
                    {
                        gps.data.gsa.type = LOCATION_TYPE_2D;
                    }
                    else if (strcmp(buf, "3") == 0)
                    {
                        gps.data.gsa.type = LOCATION_TYPE_3D;
                    }
                }
                break;

                default:
                    if (dot_count > dot_c - 1 - 3) // 获取精度因子
                    {
                        switch (dot_c - dot_count)
                        {
                        case 3:
                        {
                            sscanf(buf, "%lf", &gps.data.gsa.PDOP);
                        }
                        break;
                        case 2:
                        {
                            sscanf(buf, "%lf", &gps.data.gsa.HDOP);
                        }
                        break;
                        case 1:
                        {
                            sscanf(buf, "%lf", &gps.data.gsa.VDOP);
                        }
                        break;
                        case 0:
                        {
                            sscanf(buf, "%d", &gps.data.gsa.systemid);
                        }
                        break;

                        default:
                            break;
                        }
                    }
                    else // 获取卫星编号
                    {
                        sscanf(buf, "%02d", &gps.data.gsa.satellite_index[sate_index++]);
                    }
                    break;
                }
            }
            len = 0;
            dot_count++;
        }
        else
        {
            len++;
        }
    }

    printf("dot count[%d]\n", dot_count);
}
static void gps_parse_vtg(char *str)
{
    if (str == NULL)
    {
        return;
    }

    char buf[20] = {0};
    int index = 0, len = 0, len_count = 0, dot_count = 0, last_len = 0;
    for (int i = 0; i <= strlen(str); i++)
    {
        // printf("[%c]\t", str[i]);
        if (str[i] == ',' || str[i] == '*' || i == strlen(str))
        {
            if (len > 0)
            {
                memset(buf, 0, sizeof(buf));

                memcpy(buf, str + i - len, len);

                printf("[%s] ", buf);

                switch (dot_count)
                {
                case 1: // 获取真北地面航向角度
                {
                    sscanf(buf, "%03d", &gps.data.vtg.ground_course_true);
                }
                break;
                case 2: // 获取磁北地面航向角度
                {
                    sscanf(buf, "%03d", &gps.data.vtg.ground_course_magnetic);
                }
                break;
                case 3: // 获取地面速度,单位节
                {
                    sscanf(buf, "%lf", &gps.data.vtg.ground_speed_knot);
                }
                break;
                case 4: // 获取地面速度,单位km/h
                {
                    sscanf(buf, "%lf", &gps.data.vtg.ground_speed_knot);
                }
                break;
                case 5: // 获取模式指示
                {
                    if (strcmp(buf, "A") == 0)
                    {
                        gps.data.vtg.mode_indication = MODE_INDICATION_A;
                    }
                    else if (strcmp(buf, "D") == 0)
                    {
                        gps.data.vtg.mode_indication = MODE_INDICATION_D;
                    }
                    else if (strcmp(buf, "E") == 0)
                    {
                        gps.data.vtg.mode_indication = MODE_INDICATION_E;
                    }
                    else if (strcmp(buf, "N") == 0)
                    {
                        gps.data.vtg.mode_indication = MODE_INDICATION_N;
                    }
                }
                break;

                default:
                    break;
                }
            }
            len = 0;
            dot_count++;
        }
        else
        {
            len++;
        }
    }

    printf("dot count[%d]\n", dot_count);
}
static void gps_parse_txt(char *str)
{
    if (str == NULL)
    {
        return;
    }

    char buf[20] = {0};
    int index = 0, len = 0, len_count = 0, dot_count = 0, last_len = 0;
    for (int i = 0; i <= strlen(str); i++)
    {
        // printf("[%c]\t", str[i]);
        if (str[i] == ',' || str[i] == '*' || i == strlen(str))
        {
            if (len > 0)
            {
                memset(buf, 0, sizeof(buf));

                memcpy(buf, str + i - len, len);

                printf("[%s] ", buf);

                switch (dot_count)
                {
                case 1: // 获取语句总数
                {
                    sscanf(buf, "%02d", &gps.data.txt.total);
                }
                break;
                case 2: // 获取语句编号
                {
                    sscanf(buf, "%02d", &gps.data.txt.index);
                }
                break;
                case 3: // 文本标识符
                {
                    sscanf(buf, "%02d", &gps.data.txt.flag);
                }
                break;
                case 4: // 文本内容
                {
                    strncpy(gps.data.txt.txt, buf, strlen(buf));
                }
                break;

                default:
                    break;
                }
            }
            len = 0;
            dot_count++;
        }
        else
        {
            len++;
        }
    }

    printf("dot count[%d]\n", dot_count);
}
static void gps_parse_zda(char *str)
{
    if (str == NULL)
    {
        return;
    }

    char buf[20] = {0};
    int index = 0, len = 0, len_count = 0, dot_count = 0, last_len = 0;
    for (int i = 0; i <= strlen(str); i++)
    {
        // printf("[%c]\t", str[i]);
        if (str[i] == ',' || str[i] == '*' || i == strlen(str))
        {
            if (len > 0)
            {
                memset(buf, 0, sizeof(buf));

                memcpy(buf, str + i - len, len);

                printf("[%s] ", buf);

                switch (dot_count)
                {
                case 1: // 获取UTC时间
                {
                    sscanf(buf, "%02d%02d%02d.%03d",
                           &gps.data.zda.utc.utc_hour,
                           &gps.data.zda.utc.utc_min,
                           &gps.data.zda.utc.utc_sec,
                           &gps.data.zda.utc.utc_msec);
                }
                break;
                case 2: // 获取天
                {
                    sscanf(buf, "%02d", &gps.data.zda.day);
                }
                break;
                case 3: // 获取月
                {
                    sscanf(buf, "%02d", &gps.data.zda.mon);
                }
                break;
                case 4: // 获取年
                {
                    sscanf(buf, "%04d", &gps.data.zda.year);
                }
                break;
                case 5: // 暂不支持
                {
                    sscanf(buf, "%02d", &gps.data.zda.localhour);
                }
                break;
                case 6: // 暂不支持
                {
                    sscanf(buf, "%02d", &gps.data.zda.localmin);
                }
                break;

                default:
                    break;
                }
            }
            len = 0;
            dot_count++;
        }
        else
        {
            len++;
        }
    }

    printf("dot count[%d]\n", dot_count);
}
static void gps_parse_gll(char *str)
{
    if (str == NULL)
    {
        return;
    }

    char buf[20] = {0};
    int index = 0, len = 0, len_count = 0, dot_count = 0, last_len = 0;
    for (int i = 0; i <= strlen(str); i++)
    {
        // printf("[%c]\t", str[i]);
        if (str[i] == ',' || str[i] == '*' || i == strlen(str))
        {
            if (len > 0)
            {
                memset(buf, 0, sizeof(buf));

                memcpy(buf, str + i - len, len);

                printf("[%s] ", buf);

                switch (dot_count)
                {
                case 1: // 获取纬度
                {
                    sscanf(buf, "%lf", &gps.data.gll.latitude);
                }
                break;
                case 2: // 获取纬度方向
                {
                    if (strcmp(buf, "N") == 0)
                    {
                        gps.data.gll.latitude_hemisphere = HEMISPHERE_NORTH;
                    }
                    else if (strcmp(buf, "S") == 0)
                    {
                        gps.data.gll.latitude_hemisphere = HEMISPHERE_SOUTH;
                    }
                }
                break;
                case 3: // 获取经度
                {
                    sscanf(buf, "%lf", &gps.data.gll.longitude);
                }
                break;
                case 4: // 获取经度方向
                {
                    if (strcmp(buf, "E") == 0)
                    {
                        gps.data.gll.longitude_hemisphere = HEMISPHERE_EAST;
                    }
                    else if (strcmp(buf, "W") == 0)
                    {
                        gps.data.gll.longitude_hemisphere = HEMISPHERE_WEST;
                    }
                }
                break;
                case 5: // 获取UTC时间
                {
                    sscanf(buf, "%02d%02d%02d.%03d",
                           &gps.data.gll.utc.utc_hour,
                           &gps.data.gll.utc.utc_min,
                           &gps.data.gll.utc.utc_sec,
                           &gps.data.gll.utc.utc_msec);
                }
                break;
                case 6: // 获取定位系统状态
                {
                    if (strcmp(buf, "A") == 0)
                    {
                        gps.data.gll.location_state = LOCATION_NORMAL;
                    }
                    else if (strcmp(buf, "V") == 0)
                    {
                        gps.data.gll.location_state = LOCATION_INVALID;
                    }
                }
                break;
                case 7: // 获取定位指示
                {
                    if (strcmp(buf, "A") == 0)
                    {
                        gps.data.gll.mode_indication = MODE_INDICATION_A;
                    }
                    else if (strcmp(buf, "D") == 0)
                    {
                        gps.data.gll.mode_indication = MODE_INDICATION_D;
                    }
                    else if (strcmp(buf, "E") == 0)
                    {
                        gps.data.gll.mode_indication = MODE_INDICATION_E;
                    }
                    else if (strcmp(buf, "N") == 0)
                    {
                        gps.data.gll.mode_indication = MODE_INDICATION_N;
                    }
                }
                break;
                default:
                    break;
                }
            }
            len = 0;
            dot_count++;
        }
        else
        {
            len++;
        }
    }

    printf("dot count[%d]\n", dot_count);
}

uint8_t gps_checksum(char *str)
{
    uint8_t checksum = 0, *checksum_str;
    checksum_str = str;
    while (*checksum_str)
    {
        if (*checksum_str == '$')
        {
            checksum_str++;
            continue;
        }
        else if (*checksum_str == '*')
        {
            break;
        }
        checksum ^= *checksum_str;
        checksum_str++;
    }
    // printf("%02x\n", checksum);

    return checksum;
}

void dq_parse_gps(char *str)
{
    // uint8_t *gps_str = {"$GNZDA,090944.000,16,12,2022,00,00*4E"};
    // uint8_t *gps_str = {"$GPTXT,01,01,01,ANTENNA OK*35"};
    // uint8_t *gps_str = {"$GNGGA,090945.004,3205.20197,N,11852.59108,E,1,06,5.1,9.7,M,0.9,M,,*71"};
    // uint8_t *gps_str = {"$GNGLL,3205.20197,N,11852.59108,E,090945.004,A,A*41"};
    // uint8_t *gps_str = {"$GNGSA,A,3,10,36,40,,,,,,,,,,8.0,5.1,6.2,4*3C"};
    // uint8_t *gps_str = {"$GNRMC,090944.000,V,,,,,,,161222,,,N,V*2D"};
    // uint8_t *gps_str = {"$GPGSV,2,1,05,04,49,243,34,08,57,215,36,09,35,291,37,27,,,29,0*5E"};
    // uint8_t *gps_str = {"$GNVTG,,,,,,,,,N*2E"};
    uint8_t *gps_str = str;
    printf("\n\n****************\n%s\n", gps_str);

    memcpy(gps.address.talker, gps_str + 1, 2);
    memcpy(gps.address.SentenceFormatter, gps_str + 3, 3);

    uint8_t buf[3] = {0};
    memcpy(buf, gps_str + strlen(gps_str) - 2, 2);
    sscanf(buf, "%02x", &gps.checksum);

    printf("[%s %s %02x]\n",
           gps.address.talker,
           gps.address.SentenceFormatter,
           gps.checksum);

    // 校验数据完整性
    if (gps.checksum != gps_checksum(gps_str))
    {
        printf("data checksum fail!!! \n%02x vs %02x\n", gps.checksum, gps_checksum(gps_str));
        return;
    }

    // if (strcmp(gps.address.talker, "GP") == 0) // GPS
    // {
    //     printf("GPS\t");
    // }
    // else if (strcmp(gps.address.talker, "GL") == 0) // GLONASS
    // {
    //     printf("GLONASS\t");
    // }
    // else if (strcmp(gps.address.talker, "BD") == 0) // 北斗
    // {
    //     printf("BD\t");
    // }
    // else if (strcmp(gps.address.talker, "GP") == 0) // QZSS
    // {
    //     printf("QZSS\t");
    // }
    // else if (strcmp(gps.address.talker, "GN") == 0) // 组合星系
    // {
    //     printf("GN\t");
    // }

    // 解析数据
    if (strcmp(gps.address.SentenceFormatter, "RMC") == 0) // RMC 推荐定位信息
    {
        gps_parse_rmc(gps_str);

        printf("%d %d %d %d %d %d %d \n%d \n%f %d %f %d \n%f %f %f \n%d %d\n",
               gps.data.rmc.utc.utc_year,
               gps.data.rmc.utc.utc_mon,
               gps.data.rmc.utc.utc_day,
               gps.data.rmc.utc.utc_hour,
               gps.data.rmc.utc.utc_min,
               gps.data.rmc.utc.utc_sec,
               gps.data.rmc.utc.utc_msec,
               gps.data.rmc.location_state,
               gps.data.rmc.latitude,
               gps.data.rmc.latitude_hemisphere,
               gps.data.rmc.longitude,
               gps.data.rmc.longitude_hemisphere,
               gps.data.rmc.ground_speed,
               gps.data.rmc.ground_course,
               gps.data.rmc.declination,
               gps.data.rmc.declination_course,
               gps.data.rmc.mode_indication);
    }
    else if (strcmp(gps.address.SentenceFormatter, "GGA") == 0) // GGA 固定数据输出
    {
        gps_parse_gga(gps_str);

        printf("%d %d %d %d %d %d %d \n%f %d %f %d \n%d %d \n%f %f %f \n%d %d\n",
               gps.data.gga.utc.utc_year,
               gps.data.gga.utc.utc_mon,
               gps.data.gga.utc.utc_day,
               gps.data.gga.utc.utc_hour,
               gps.data.gga.utc.utc_min,
               gps.data.gga.utc.utc_sec,
               gps.data.gga.utc.utc_msec,
               gps.data.gga.latitude,
               gps.data.gga.latitude_hemisphere,
               gps.data.gga.longitude,
               gps.data.gga.longitude_hemisphere,
               gps.data.gga.location_state,
               gps.data.gga.satellites_count,
               gps.data.gga.precision_level,
               gps.data.gga.sea_level,
               gps.data.gga.ground_level,
               gps.data.gga.differential_data_life,
               gps.data.gga.differential_data_bsn);
    }
    else if (strcmp(gps.address.SentenceFormatter, "GSV") == 0) // GSV 可视卫星状态输出语句
    {
        gps_parse_gsv(gps_str);

        printf("%d %d %d %d\n",
               gps.data.gsv.message_num,
               gps.data.gsv.message_index,
               gps.data.gsv.visible_count,
               gps.data.gsv.signalid);

        for (int i = 0; i < GSV_NUM_MAX; i++)
        {
            if (gps.data.gsv.satellite_index[i] != 0)
            {
                printf("%d %d %d %d\n",
                       gps.data.gsv.satellite_index[i],
                       gps.data.gsv.satellite_elevation[i],
                       gps.data.gsv.satellite_azimuth[i],
                       gps.data.gsv.satellite_snr[i]);
            }
        }
    }
    else if (strcmp(gps.address.SentenceFormatter, "GSA") == 0) // GSA 当前卫星信息
    {
        gps_parse_gsa(gps_str);

        printf("%d %d %d \n%f %f %f %d\n",
               gps.data.gsa.mode,
               gps.data.gsa.type,
               gps.data.gsa.satellite_index[0],
               gps.data.gsa.PDOP,
               gps.data.gsa.HDOP,
               gps.data.gsa.VDOP,
               gps.data.gsa.systemid);

        for (int i = 0; i < GSV_NUM_MAX; i++)
        {
            if (gps.data.gsa.satellite_index[i] != 0)
            {
                printf("%d ", gps.data.gsa.satellite_index[i]);
            }
        }
    }
    else if (strcmp(gps.address.SentenceFormatter, "VTG") == 0) // 地面速度
    {
        gps_parse_vtg(gps_str);

        printf("%d %d %d %d %d\n",
               gps.data.vtg.ground_course_true,
               gps.data.vtg.ground_course_magnetic,
               gps.data.vtg.ground_speed_knot,
               gps.data.vtg.ground_speed_km,
               gps.data.vtg.mode_indication);
    }
    else if (strcmp(gps.address.SentenceFormatter, "ZDA") == 0) // 输出 UTC 时间，日、月、年及本地时区
    {
        gps_parse_zda(gps_str);
        printf("%d %d %d %d %d %d %d \n%d %d %d\n",
               gps.data.zda.utc.utc_year,
               gps.data.zda.utc.utc_mon,
               gps.data.zda.utc.utc_day,
               gps.data.zda.utc.utc_hour,
               gps.data.zda.utc.utc_min,
               gps.data.zda.utc.utc_sec,
               gps.data.zda.utc.utc_msec,
               gps.data.zda.day,
               gps.data.zda.mon,
               gps.data.zda.year,
               gps.data.zda.localhour,
               gps.data.zda.localmin);
    }
    else if (strcmp(gps.address.SentenceFormatter, "TXT") == 0) // 文本消息
    {
        gps_parse_txt(gps_str);

        printf("%d %d %d %s\n",
               gps.data.txt.total,
               gps.data.txt.index,
               gps.data.txt.flag,
               gps.data.txt.txt);
    }
    else if (strcmp(gps.address.SentenceFormatter, "GLL") == 0) // 地理位置
    {
        gps_parse_gll(gps_str);

        printf("%f %d %f %d \n%d %d %d %d %d %d %d \n%d %d\n",
               gps.data.gll.latitude,
               gps.data.gll.latitude_hemisphere,
               gps.data.gll.longitude,
               gps.data.gll.longitude_hemisphere,
               gps.data.gll.utc.utc_year,
               gps.data.gll.utc.utc_mon,
               gps.data.gll.utc.utc_day,
               gps.data.gll.utc.utc_hour,
               gps.data.gll.utc.utc_min,
               gps.data.gll.utc.utc_sec,
               gps.data.gll.utc.utc_msec,
               gps.data.gll.location_state,
               gps.data.gll.mode_indication);
    }
}

void check_sum(int argc, char *argv[])
{
    printf("ex:check sum[hex value]\n");
    int check_sum = 0;
    char *content = argv[1];
    while (*content)
    {
        check_sum ^= *content;
        content++;
    }
    printf("check_sum[%02X]\n", check_sum);
}

void gps_raw_data_parse()
{
    uint8_t *raw_str = {"$GNGLL,,,,,,V,N*7A $GNGSA,A,1,,,,,,,,,,,,,25.5,25.5,25.5,1*01 $GNGSA,A,1,,,,,,,,,,,,,25.5,25.5,25.5,4*04 $GPGSV,1,1,00,0*65 $BDGSV,1,1,00,0*74 "};
    printf("%s\n", raw_str);

    uint8_t buf[300] = {0};
    int len = 0, index = 0, dot_count = 0;

    for (int i = 0; i < strlen(raw_str); i++)
    {
        if (raw_str[i] == '$')
        {
            printf("index %d len %d\t ", index, len);
            memset(buf, 0, sizeof(buf));
            memcpy(buf, raw_str + i - len - 1, len);

            dot_count++;
            index += len;
            len = 0;

            // printf("[%s]\n", buf);
            dq_parse_gps(buf);
        }
        else
        {
            len++;
        }
    }
}
